package org.jeecg.modules.car.web;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.CommonDefine;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.StringUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.GetRequestJsonUtils;
import org.jeecg.config.JsonMapper;
import org.jeecg.config.Sm4Util;
import org.jeecg.entity.car.CarDerateDetails;
import org.jeecg.entity.car.CarMerchantDerate;
import org.jeecg.entity.car.CarTencentCarNo;
import org.jeecg.enums.*;
import org.jeecg.enums.car.CarDerateStatusEnum;
import org.jeecg.enums.car.CarDerateTypeEnum;
import org.jeecg.enums.car.CarIsSysMerchantTypeEnum;
import org.jeecg.enums.common.PayTypeEnum;
import org.jeecg.modules.car.entity.CarMerchant;
import org.jeecg.modules.car.entity.CarMerchantOrder;
import org.jeecg.modules.car.entity.CarPayNotify;
import org.jeecg.modules.car.service.*;
import org.jeecg.modules.car.service.impl.ForeignCarJGSService;
import org.jeecg.modules.car.service.impl.SyncCarServiceImpl;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.vo.car.ForeignCarIotPayTempReq;
import org.jeecg.vo.car.ForeignCarMerchantPayReq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 车禁商家 - 对外接口
 *
 * @author liurui
 * @version v1.0
 * @date 2020年10月21日
 */
@Slf4j
@RestController
@Api(tags="商家管理公众号")
@RequestMapping(value = "/b/foreign/carMerchant")
public class ForeignCarMerchantController {

    @Autowired
    private ICarMerchantService carMerchantService;
    @Autowired
    private ICarMerchantDerateService carMerchantDerateService;
    @Autowired
    private ICarMerchantOrderService carMerchantOrderService;
    @Autowired
    private ICarDerateDetailsService carDerateDetailsService;
    @Autowired
    private SyncCarServiceImpl syncCarService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ForeignCarJGSService foreignCarJGSService;
    @Autowired
    private ICarTencentCarNoService carTencentCarNoService;
//    //    private static  final String key = "04720B3F2FAD4612B5A9FEFF7B20ADA9"; //
//    private static  final String key = "5F71191D102F2292DF9E11D8BA35BBB0"; //正式

    @Value("${pay.fftEncryptKey}")
    private String fftEncryptKey; //付费通加密key

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    @ApiOperation("商户登录接口")
    public Result<JSONObject> login(HttpServletRequest request, SysLoginModel sysLoginModel) throws Exception {
        log.info("商户登录接口接受数据:{}",sysLoginModel);
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        //步骤1：TODO 前端密码加密，后端进行密码解密，防止传输密码篡改等问题，不配就直接提示密码错误，并记录日志后期进行统计分析是否锁定
//        password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword()).trim();//密码解密
        //1. 校验用户是否有效
        CarMerchant merchant = carMerchantService.getUserByName(username);
        if (merchant == null){
            result.error500("用户不存在");
            return result;
        }
        //2. 校验用户名或密码是否正确
//        String userpassword = PasswordUtil.encrypt(username, password, merchant.getSalt());
        String syspassword = merchant.getLoginPwd();
        if (!syspassword.equals(password)) {
            log.error("运算pass -> "+ password);
            result.error500("密码输入错误");
            return result;
        }
        //用户登录信息
        userInfo(merchant,result);
        return result;
    }

    @RequestMapping(value = "/getCarMerchantDetail", method = RequestMethod.GET)
    @ApiOperation("商户详细信息")
    public Result<JSONObject> getCarMerchantDetail(String merchantId,HttpServletRequest request) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        try {
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            JSONObject obj = new JSONObject();
            obj.put("token", accessToken);
            obj.put("merchant", carMerchant);
            result.setResult(obj);
            result.setMessage("成功");
        }catch (RuntimeException re){
            log.error("商户详细信息:{}",re.getMessage());
            return Result.error(re.getMessage());
        }
        return result;
    }

    @RequestMapping(value = "/getMerchantCarNo", method = RequestMethod.GET)
    @ApiOperation("获取商户常用车牌信息")
    public Result<JSONObject> getMerchantCarNo(HttpServletRequest request) throws Exception {
        log.info("获取商户常用车牌信息...");
        Result<JSONObject> result = new Result<JSONObject>();
        try {
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            CarTencentCarNo carTencentCarNo = new CarTencentCarNo();
            carTencentCarNo.setMerchantId(carMerchant.getId());
            carTencentCarNo.setTenantId(carMerchant.getTenantId());
            List<CarTencentCarNo> carNos = carTencentCarNoService.getByMerchantIdCarNo(carTencentCarNo);
            JSONObject obj = new JSONObject();
            obj.put("carNos", carNos);
            result.setResult(obj);
            result.setMessage("成功");
        }catch (RuntimeException re){
            log.error("获取商户常用车牌信息失败:{}",re.getMessage());
            return Result.error(re.getMessage());
        }
        return result;
    }

    @RequestMapping(value = "/delMerchantCarNo", method = RequestMethod.GET)
    @ApiOperation("删除商户常用车牌信息")
    public Result<JSONObject> delMerchantCarNo(String carNo, HttpServletRequest request) throws Exception {
        log.info("删除商户常用车牌信息：{}",carNo);
        Result<JSONObject> result = new Result<JSONObject>();
        try {
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            CarTencentCarNo carTencentCarNo = new CarTencentCarNo();
            carTencentCarNo.setMerchantId(carMerchant.getId());
            carTencentCarNo.setTenantId(carMerchant.getTenantId());
            carTencentCarNo.setCarNo(carNo);
            List<CarTencentCarNo> carNos = carTencentCarNoService.getByMerchantIdCarNo(carTencentCarNo);
            if (carNos.size() <= 0){
                result.setMessage("未查询到当前车牌信息");
                return result;
            }
            carTencentCarNoService.removeById(carNos.get(0));
            result.setCode(200);
            result.setMessage("删除成功");
        }catch (RuntimeException re){
            log.error("删除商户常用车牌信息失败:{}",re.getMessage());
            return Result.error(re.getMessage());
        }
        return result;
    }

    @RequestMapping(value = "/saveMerchantCarNo", method = RequestMethod.GET)
    @ApiOperation("保存商户常用车牌信息")
    public Result<JSONObject> saveMerchantCarNo(String carNo, HttpServletRequest request) throws Exception {
        log.info("添加商户常用车牌信息：{}",carNo);
        Result<JSONObject> result = new Result<JSONObject>();
        try {
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            CarTencentCarNo carTencentCarNo = new CarTencentCarNo();
            carTencentCarNo.setMerchantId(carMerchant.getId());
            carTencentCarNo.setTenantId(carMerchant.getTenantId());
            List<CarTencentCarNo> carNos = carTencentCarNoService.getByMerchantIdCarNo(carTencentCarNo);
            if (carNos.size() >= 20){
                result.setMessage("常用车牌最多保存20个");
                return result;
            }
            carTencentCarNo.setCarNo(carNo);
            carNos = carTencentCarNoService.getByMerchantIdCarNo(carTencentCarNo);
            if (carNos.size() > 0){
                result.setMessage("常用车牌已经存在，请勿重复添加");
                return result;
            }
            carTencentCarNo = new CarTencentCarNo();
            carTencentCarNo.setMerchantId(carMerchant.getId());
            carTencentCarNo.setTenantId(carMerchant.getTenantId());
            carTencentCarNo.setCarNo(carNo);
            carTencentCarNoService.save(carTencentCarNo);
            result.setMessage("保存成功");
            result.setCode(200);
        }catch (RuntimeException re){
            log.error("保存商户常用车牌信息失败:{}",re.getMessage());
            return Result.error(re.getMessage());
        }
        return result;
    }

    @AutoLog(value = "商户修改重置接口")
    @ApiOperation(value = "商户修改重置接口", notes = "商户修改重置接口")
    @PostMapping(value = "/reset")
    public Result<JSONObject> reset(String oldPwd,String newPwd,String newPwd2,HttpServletRequest request)  {
        try {
            //判断是否有登录
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            if (!oldPwd.equals(carMerchant.getLoginPwd())){
                return Result.error("原始密码输入错误！");
            }
            if (!newPwd.equals(newPwd2)){
                return Result.error("2次密码输入不一致！");
            }
            if (StringUtils.isBlank(carMerchant.getRemarks())){
                carMerchant.setRemarks("");
            }
            carMerchant.setRemarks(carMerchant.getRemarks() + "-已修改密码");
            int res = carMerchantService.updatePwd(carMerchant.getId(),newPwd,carMerchant.getRemarks());
            if (res > 0){
                return Result.ok("修改密码成功");
            }
        }catch (RuntimeException re){
            log.error(re.getMessage(),re);
            return Result.error(re.getMessage());
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
        return Result.error("修改失败");
    }

    @AutoLog(value = "商户退出登录")
    @ApiOperation(value = "商户退出登录", notes = "商户退出登录")
    @PostMapping(value = "/logout")
    public Result<JSONObject> logout(HttpServletRequest request) throws Exception {
        try {
            String token = request.getHeader("X-Access-Token");
            //清空用户Token缓存
            redisUtil.del(CommonConstant.PREFIX_MERCHANT_TOKEN + token);
            return Result.ok("退出登录成功！");
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
        return Result.error("失败");
    }


    @AutoLog(value = "商家优惠券列表")
    @ApiOperation(value = "商家优惠券列表", notes = "商家优惠券列表")
    @GetMapping(value = "/derateList")
    public Result<IPage<CarMerchantDerate>> derateList(CarMerchantDerate carMerchantDerate,
                                                       @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                                       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                                       HttpServletRequest req){
        log.info("查询商家优惠券列表：" + carMerchantDerate);
        Result<IPage<CarMerchantDerate>> result = new Result<IPage<CarMerchantDerate>>();
        try {
            //判断是否有登录
            String accessToken = req.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            carMerchantDerate.setMerchantId(carMerchant.getId());
           /* LambdaQueryWrapper<CarMerchantDerate> query = new LambdaQueryWrapper<>();
            //查询当前商户优惠券
            query.eq(CarMerchantDerate::getMerchantId, carMerchantDerate.getMerchantId());
            if (StringUtils.isNotBlank(carMerchantDerate.getDerateMode())){
                query.eq(CarMerchantDerate::getDerateMode, carMerchantDerate.getDerateMode());
            }
            Page<CarMerchantDerate> page = new Page<CarMerchantDerate>(pageNo, pageSize);
            IPage<CarMerchantDerate> pageList = carMerchantDerateService.page(page, query);*/
            Page<CarMerchantDerate> page = new Page<CarMerchantDerate>(pageNo, pageSize);
            page.setRecords(carMerchantDerateService.derateList(page,carMerchantDerate));
            result.setSuccess(true);
            result.setResult(page);
            //result.setResult(pageList);
        }catch (RuntimeException re){
            log.error(re.getMessage(),re);
            return Result.error(re.getMessage());
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return Result.error("查询失败");
        }
        return result;
    }

    @AutoLog(value = "折扣二维码详情")
    @ApiOperation(value = "折扣二维码详情", notes = "折扣二维码详情")
    @GetMapping(value = "/derateDetail/{derateId}")
    public Result<CarMerchantDerate> derateDetail(@PathVariable String derateId){
        try {
            log.info("折扣二维码详情:{}",derateId);
            CarMerchantDerate carMerchantDerate = carMerchantDerateService.getById(derateId);
            if (carMerchantDerate == null){
                return Result.error("优惠券不存在！");
            }
            CarMerchant merchant = carMerchantService.getById(carMerchantDerate.getMerchantId());
            if (merchant != null){
                carMerchantDerate.setMerchantName(merchant.getName());
            }
            carMerchantDerate.setDeratePayUrl("https://b.ian9.cn/i/car/foreign/carMerchant/doDerate/" + derateId);
            return Result.ok(carMerchantDerate);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return Result.error("查询失败");
        }
    }

    @AutoLog(value = "扫码打折详情")
    @ApiOperation(value = "扫码打折详情", notes = "扫码打折详情")
    @PostMapping(value = "/doDerate/{derateId}")
    public Result<CarMerchantDerate> doDerate(@PathVariable String derateId){
        try {
            log.info("扫码打折详情:{}",derateId);
            CarMerchantDerate carMerchantDerate = carMerchantDerateService.getById(derateId);
            if (carMerchantDerate == null){
                return Result.error("优惠券不存在！");
            }
            if (carMerchantDerate.getEndTime().compareTo(new Date()) <= 0){
                return Result.error("优惠券已过有效期！");
            }
            if (!carMerchantDerate.getStatus().equals(CarDerateStatusEnum.CAR_DERATE_STATUS_0.getCode())){
                return Result.error("优惠券已被使用！");
            }
            CarMerchant merchant = carMerchantService.getById(carMerchantDerate.getMerchantId());
            if (merchant != null){
                carMerchantDerate.setMerchantName(merchant.getName());
            }
            return Result.ok(carMerchantDerate);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return Result.error("查询失败");
        }
    }

    @AutoLog(value = "商家删除优惠券")
    @ApiOperation(value="商家删除优惠券", notes="商家删除优惠券")
    @GetMapping(value = "/delDerate")
    public Result<String> delDerate(String derateId, HttpServletRequest request){
        try {
            //判断是否有登录
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            return carMerchantDerateService.delDerate(carMerchant, derateId);
        }catch (RuntimeException re){
            log.error(re.getMessage(),re);
            return Result.error(re.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return Result.error("操作失败");
        }
    }

    @AutoLog(value = "商家添加/复制优惠券")
    @ApiOperation(value="商家添加/复制优惠券", notes="商家添加/复制优惠券")
    @PostMapping(value = "/addDerate")
    public Result<String> addDerate(CarMerchantDerate carMerchantDerate,HttpServletRequest request) {
        try {
            log.info("商家添加/复制优惠券:{}", carMerchantDerate);
            //判断是否有登录
            String accessToken = request.getHeader("X-Access-Token");
            //商户信息
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
//            if (!carMerchant.getTenantId().equals("1")){
//                return Result.error("暂未开通");
//            }
            //判断余额
            BigDecimal remainAmount = carMerchant.getRemainAmount();
            //赠送余额
            BigDecimal donateAmount = carMerchant.getDonateAmount();
            //优惠券金额 = 金额  *  数量
            BigDecimal derateAmount = carMerchantDerate.getDerateAmount().multiply(BigDecimal.valueOf(carMerchantDerate.getUsableNumber()));
            //本次使用后的余额
            BigDecimal endAmount = remainAmount;
            // 优惠券生成方式 0余额生成 1赠送余额生成
            Integer derateSource;
            if (donateAmount.compareTo(derateAmount) < 0){
                //赠送金额不足以抵扣
                //可透支金额
                BigDecimal overdraftAmount = carMerchant.getOverdraftAmount();
                overdraftAmount = overdraftAmount.negate(); //负数
                endAmount = remainAmount.subtract(derateAmount);
                derateSource = 0;
                if (endAmount.compareTo(overdraftAmount) < 0) {
                    return Result.error("账户余额已透支，请尽快充值！");
                }

            }else {
                donateAmount = donateAmount.subtract(derateAmount);
                derateSource = 1;
            }
            //判断优惠券添加类型  是系统商家还是非系统商家
            if (carMerchant.getIsSysMerchant().equals(CarIsSysMerchantTypeEnum.CAR_IS_SYS_MERCHANT_1)){
                carMerchantDerate.setDerateType(CarDerateTypeEnum.CAR_DERATE_TYPE_2.getCode());
            }else {
                carMerchantDerate.setDerateType(CarDerateTypeEnum.CAR_DERATE_TYPE_0.getCode());
            }
            carMerchantDerate.setId(null);
            //carMerchantDerate.setUsableNumber(1);
            carMerchantDerate.setUsedNumber(0);
            carMerchantDerate.setStatus(CarDerateStatusEnum.CAR_DERATE_STATUS_0.getCode());
            carMerchantDerate.setDerateMode("1");
            carMerchantDerate.setTenantId(carMerchant.getTenantId());
            carMerchantDerate.setProjectId(carMerchant.getProjectId());
            carMerchantDerate.setMerchantId(carMerchant.getId());
            carMerchantDerate.setCreateBy(carMerchant.getId());
            carMerchantDerate.setUpdateBy(carMerchant.getId());
            carMerchantDerate.setRemainAmount(endAmount);
            carMerchantDerate.setDonateAmount(donateAmount);
            carMerchantDerate.setDerateSource(derateSource);
            carMerchant.setRemainAmount(endAmount);
            carMerchant.setDonateAmount(donateAmount);
            carMerchantDerateService.add(carMerchantDerate, carMerchant);
            return Result.ok("添加成功！");
        }catch (RuntimeException re){
            log.error(re.getMessage(),re);
            return Result.error(re.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return Result.error("操作失败");
        }
    }

    @AutoLog(value = "商家编辑优惠券")
    @ApiOperation(value="商家编辑优惠券", notes="商家编辑优惠券")
    @PostMapping(value = "/editDerate")
    public Result<String> editDerate(@RequestBody CarMerchantDerate carMerchantDerate,HttpServletRequest request) {
        try {
            log.info("商家编辑优惠券:{}", carMerchantDerate);
            //判断是否有登录
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            CarMerchantDerate existBean = carMerchantDerateService.getById(carMerchantDerate.getId());
            if (existBean == null) {
                return Result.error("优惠券系统中不存在！");
            }
            //已失效,已使用的不可编辑
            if (CarDerateStatusEnum.CAR_DERATE_STATUS_2.getCode().equals(existBean.getStatus())
                    || CarDerateStatusEnum.CAR_DERATE_STATUS_MISS.getCode().equals(existBean.getStatus())) {
                return Result.error("已使用或已失效优惠券不可编辑！");
            }
            //系统优惠券不可编辑
            if (existBean.getDerateType().intValue() == 1) {
                return Result.error("系统发放的优惠券不可编辑！");
            }
            //有效期校验
            if (carMerchantDerate.getStartTime() != null && carMerchantDerate.getStartTime().compareTo(carMerchantDerate.getEndTime()) >= 0) {
                return Result.error("优惠券的开始时间不能大于结束时间！");
            }
            Date now = new Date();
            if (carMerchantDerate.getEndTime() != null && carMerchantDerate.getEndTime().compareTo(now) <= 0) {
                return Result.error("优惠券结束时间不能小于当前时间！");
            }
            //现有账号的余额
            BigDecimal remainAmount = carMerchant.getRemainAmount();
            //可透支金额
            BigDecimal overdraftAmount = carMerchant.getOverdraftAmount();
            overdraftAmount = overdraftAmount.negate(); //负数
            //优惠券上的金额
            BigDecimal derateAmount = carMerchantDerate.getDerateAmount();
            if (derateAmount.compareTo(existBean.getDerateAmount()) != 0) {  //金额有改动
                //多退少补
                BigDecimal mergeAmount = existBean.getDerateAmount().subtract(derateAmount);
                //扣券后的账户余额
                BigDecimal endAmount = remainAmount.subtract(mergeAmount);
                if (endAmount.compareTo(overdraftAmount) < 0) {
                    return Result.error("账户余额已透支，请尽快充值！");
                }
                carMerchant.setRemainAmount(endAmount);
                carMerchantDerateService.editDerate(carMerchantDerate, carMerchant);
            } else {
                carMerchantDerateService.editDerate(carMerchantDerate, null);
            }
            return Result.ok("添加成功！");
        } catch (RuntimeException re){
            log.error(re.getMessage(),re);
            return Result.error(re.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return Result.error("操作失败");
        }
    }

    @AutoLog(value = "商家手动输入车牌号-进行减免")
    @ApiOperation(value="商家手动输入车牌号-进行减免", notes="商家手动输入车牌号-进行减免")
    @PostMapping(value = "/entryDerate")
    public Result<String> entryDerate(@ApiParam(value ="待减免的车牌号",required = true) @RequestParam(name="plate") String plate,
                                      @ApiParam(value ="应收金额",required = true) @RequestParam(name="dueAmount") BigDecimal dueAmount,
                                      @ApiParam(value ="减免金额",required = true) @RequestParam(name="derateAmount") BigDecimal derateAmount,
                                      @ApiParam(value ="进场记录id",required = true) @RequestParam(name="recordId") String recordId,
                                      @ApiParam(value ="车禁平台订单号",required = true) @RequestParam(name="orderNo") String orderNo,
                                      @ApiParam(value ="车禁平台车场id",required = true) @RequestParam(name="parkId") String parkId,
                                      HttpServletRequest request) {
        try {
            log.info("商家手动输入车牌号-进行减免接收参数:plate={},dueAmount={},derateAmount={},recordId={},orderNo={},parkId={}", plate,dueAmount,derateAmount,recordId,orderNo,parkId);
            if (derateAmount.compareTo(BigDecimal.ZERO) <= 0){
                return Result.error("减免金额不能小于0元！");
            }
            if (StringUtils.isBlank(recordId)){
                return Result.error("无有效进出记录！");
            }
            if (StringUtils.isBlank(orderNo)){
                return Result.error("订单号为空！");
            }
            //判断是否有登录
            String accessToken = request.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            //判断余额
            BigDecimal remainAmount = carMerchant.getRemainAmount();
            // 赠送余额
            BigDecimal donateAmount = carMerchant.getDonateAmount();
            //本次使用后的余额
            BigDecimal endAmount = remainAmount;
            // 优惠券生成方式 0余额生成 1赠送余额生成
            Integer derateSource;
            if (donateAmount.compareTo(derateAmount) < 0){
                // 赠送金额不够用 不使用赠送金额 使用余额支付
                //可透支金额
                BigDecimal overdraftAmount = carMerchant.getOverdraftAmount();
                overdraftAmount = overdraftAmount.negate(); //负数
                endAmount = remainAmount.subtract(derateAmount);
                derateSource = 0;
                if (endAmount.compareTo(overdraftAmount) < 0) {
                    return Result.error("账户余额已透支，请尽快充值！");
                }
            }else {
                // 用赠送金额抵扣
                donateAmount = donateAmount.subtract(derateAmount);
                derateSource = 1;
            }
            //判断是否重复打折
            CarDerateDetails exist = carDerateDetailsService.getDerateDetail(plate);
//            CarMerchantDerate  exist =  carMerchantDerateService.getByPlateStatus(plate,CarDerateStatusEnum.CAR_DERATE_STATUS_1.getCode());
            if (exist != null){
                return Result.error("当前车辆已经打过折了，请勿重复打折");
            }
            CarMerchantDerate carMerchantDerate = new CarMerchantDerate();
            carMerchantDerate.setUsableNumber(1);
            carMerchantDerate.setUsedNumber(1);
            carMerchantDerate.setStatus(CarDerateStatusEnum.CAR_DERATE_STATUS_2.getCode());  //车辆扫码支付时查询条件：已发送 + usedNumber为0时的记录 - 删   改从明细表里查询
            carMerchantDerate.setTenantId(carMerchant.getTenantId());
            carMerchantDerate.setProjectId(carMerchant.getProjectId());
            carMerchantDerate.setMerchantId(carMerchant.getId());
            carMerchantDerate.setPlateNumber(plate);
            carMerchantDerate.setDerateType(CarDerateTypeEnum.CAR_DERATE_TYPE_3.getCode());
            carMerchantDerate.setDerateMode("1");
            carMerchantDerate.setDerateAmount(derateAmount);
            carMerchantDerate.setRemainAmount(endAmount);
            carMerchantDerate.setDonateAmount(donateAmount);
            carMerchantDerate.setCreateBy(carMerchant.getId());
            carMerchantDerate.setUpdateBy(carMerchant.getId());
            carMerchantDerate.setDerateSource(derateSource);
            carMerchant.setRemainAmount(endAmount);
            carMerchant.setDonateAmount(donateAmount);
            if (derateAmount.compareTo(dueAmount) >= 0 ){  //减免金额大于等于应付金额
                //通知车禁开闸
                ForeignCarIotPayTempReq tempReq = new ForeignCarIotPayTempReq();
                tempReq.setOrder_no(orderNo);
                tempReq.setOrder_id(StringUtils.createSn("entr",3));
                tempReq.setPay_type("2");
                tempReq.setPay_fee(derateAmount.toString());
                tempReq.setPlate_number(plate);
                tempReq.setPark_id(parkId);
                Result payRes = foreignCarJGSService.payTempCost(tempReq);
                if (!payRes.isSuccess()){
                    log.error("商家手动输入车牌号-进行减免通知车场失败",payRes.getMessage());
                    return Result.error("操作失败，" + payRes.getMessage());
                } else {
//                    carMerchantDerate.setUsedNumber(1);
                    carMerchantDerate.setUseTime(new Date());
                    carMerchantDerate.setDerateMode("0");  //全额减免
                    carMerchantDerate.setStatus(CarDerateStatusEnum.CAR_DERATE_STATUS_2.getCode());
                }
            }
            carMerchantDerateService.addDerate(carMerchantDerate, carMerchant);
        }catch (RuntimeException re){
            log.error("商家手动输入车牌号-进行减免商户未登录",re);
            return Result.error(re.getMessage());
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return Result.error("操作失败");
        }
        return Result.ok("打折成功");
    }


    @AutoLog(value = "商户充值接口")
    @ApiOperation(value="商户充值接口", notes="商户充值接口")
    @PostMapping(value = "/pay")
    public Result pay(ForeignCarMerchantPayReq payReq, HttpServletRequest req){
        try{
            log.info("商户充值接口请求数据:{}", payReq);
            if (payReq.getPayAmount().compareTo(BigDecimal.ZERO) <= 0){
                return Result.error("支付金额不可小于0元");
            }
            //判断是否有登录
            String accessToken = req.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            //实付金额
            BigDecimal actualAmount = payReq.getPayAmount().multiply(new BigDecimal(carMerchant.getDiscountScale() / (10)).setScale(2,BigDecimal.ROUND_HALF_UP));
            //设置订单字段
            CarMerchantOrder merchantOrder = new CarMerchantOrder();
            merchantOrder.setTenantId(carMerchant.getTenantId());
            merchantOrder.setMerchantId(carMerchant.getId());
            merchantOrder.setSn(payReq.getSn());
            //支付金额
            merchantOrder.setPayAmount(actualAmount);
            merchantOrder.setPayMode(payReq.getPayMode());
            if (PayModeEnum.PAY_MODE_WECHAT.getCode().equals(payReq.getPayMode())){
                merchantOrder.setPayType(PayTypeEnum.PAY_METHOD_WEIXINPAY.getCode().toString());
            }/*else if (PayModeEnum.PAY_MODE_ALIPAY.getCode().equals(payReq.getPayMode())){
                merchantOrder.setPayType(PayTypeEnum.PAY_METHOD_ALIPAY.getCode().toString());
            }*/
            merchantOrder.setTransNo(payReq.getTransNo());
            merchantOrder.setRequest(payReq.getJsonString());
            merchantOrder.setResponse(payReq.getResponse());
            //优惠金额  = 充值金额 - 实付金额
            merchantOrder.setDiscountAmount(payReq.getPayAmount().subtract(actualAmount));
            merchantOrder.setActualAmount(payReq.getPayAmount());
            merchantOrder.setPayTime(new Date());
            //支付完结余
            merchantOrder.setBalance(payReq.getPayAmount().add(carMerchant.getRemainAmount()));
            merchantOrder.setCreateBy(carMerchant.getId());
            merchantOrder.setProjectId(carMerchant.getProjectId());
            merchantOrder.setPayStatus(PayStatusEnum.PAY_STATUS_ING.getCode());
            merchantOrder.setChargeStatus(CommonDefine.PAY_STATUS_ING);
            //添加充值记录
            carMerchantOrderService.save(merchantOrder);
            syncCarService.queryPayResult(payReq.getTransNo());
            return Result.ok("处理成功");
        }catch (Exception e){
            log.error("商户充值处理异常:{}",e);
            return Result.error("处理异常");
        }
    }

    @AutoLog(value = "商户充值记录接口")
    @ApiOperation(value="商户充值记录接口", notes="商户充值记录接口")
    @GetMapping(value = "/payList")
    public Result<List<CarMerchantOrder>> payList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                  @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                  HttpServletRequest req){
        try {
            //判断是否有登录
            String accessToken = req.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            Page<CarMerchantOrder> page = new Page<CarMerchantOrder>(pageNo, pageSize);
            List<CarMerchantOrder> orderList = carMerchantOrderService.findMerchantOrderList(page, carMerchant);
            return Result.ok(orderList);
        }catch (RuntimeException re){
            log.error("商户充值记录接口未登录",re);
            return Result.error(re.getMessage());
        }catch (Exception e){
            log.error("商户充值处理异常:{}",e);
            return Result.error("处理异常");
        }
    }

    @AutoLog(value = "商户减免记录接口")
    @ApiOperation(value = "商户减免记录接口")
    @GetMapping(value = "/discountList")
    public Result<List<CarDerateDetails>> discountList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                       HttpServletRequest req){
        try {
            //判断是否有登录
            String accessToken = req.getHeader("X-Access-Token");
            CarMerchant carMerchant = checkUserTokenIsEffect(accessToken);
            Page<CarDerateDetails> page = new Page<CarDerateDetails>(pageNo, pageSize);
            List<CarDerateDetails> discountList = carMerchantService.findDiscountListByMerChantById(page,carMerchant);
            return Result.ok(discountList);
        }catch (RuntimeException re){
            log.error("商户减免记录接口未登录",re);
            return Result.error(re.getMessage());
        }catch (Exception e){
            log.error("获取数据处理异常:{}",e);
            return Result.error("处理异常");
        }
    }

    /**
     * 商户充值 - 回调地址
     *
     * @return
     */
    @RequestMapping(value = "/carPayNotify", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation("付费通商户充值回调接口")
    public String carPayNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            JSONObject jsonObject = GetRequestJsonUtils.getRequestJsonObject(request,fftEncryptKey);
            log.info("付费通回调接口接受参数：{}",jsonObject);
            CarPayNotify stu = JSON.parseObject(jsonObject.toJSONString(), CarPayNotify.class);
            redisUtil.setNxEx(CommonConstant.LOCK_MERCHANT_ORDER+stu.getTransNo(),300);
            Integer result = carMerchantOrderService.carPayNotify(stu);
            return Sm4Util.encryptEcb(fftEncryptKey,"200success");
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return Sm4Util.encryptEcb(fftEncryptKey,"error");
    }

    /**
     * 商户充值 - 回调地址
     *
     * @return
     */
    @RequestMapping(value = "/carPayCEBNotify")
    @ResponseBody
    @ApiOperation("光大商户充值回调接口")
    public void carPayCEBNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            BufferedReader reader = request.getReader();
            String json = reader.readLine();
            reader.close();
            net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(json);
            int code = jsonObject.getInt("code");
            int status = jsonObject.getInt("status");
            net.sf.json.JSONObject data = net.sf.json.JSONObject.fromObject(jsonObject.getString("data"));
            if (code == 0){
                CarPayNotify stu = new CarPayNotify();
                stu.setOrderId(data.getString("out_trade_no"));
                stu.setPaymentAmt(data.getString("amount"));
                stu.setPaymentTime(data.getString("payment_at"));
                stu.setTransNo(data.getString("transaction_number"));
                redisUtil.setNxEx(CommonConstant.LOCK_MERCHANT_ORDER+stu.getTransNo(),300);
                Integer result = carMerchantOrderService.carPayNotify(stu);
            }
            Writer out = response.getWriter();
            Map<String, Object> map = new HashMap<String, Object>();
            if (code == 0 && status == 0) {
                map.put("status", 0);
                map.put("msg", "");
                map.put("code", 0);
            } else {
                map.put("status", 1);
                map.put("msg", "");
                map.put("code", 0);
            }
            out.write(JsonMapper.getInstance().toJson(map));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    @RequestMapping(value = "/queryPayResult", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation("付费通查询")
    public void queryPayResult(String transNo,HttpServletRequest request, HttpServletResponse response) {
        try {
            syncCarService.queryPayResult(transNo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }


    /**
     * 商户信息
     *
     * @param merchant
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(CarMerchant merchant, Result<JSONObject> result) {
        String syspassword = merchant.getLoginPwd();
        String username = merchant.getLoginName().toUpperCase();
        // 生成token
        String token = JwtUtil.sign(username,CommonConstant.CLIENT_PC_B,syspassword);
        redisUtil.set(CommonConstant.PREFIX_MERCHANT_TOKEN + token, token);
        // 设置超时时间
        redisUtil.expire(CommonConstant.PREFIX_MERCHANT_TOKEN + token, JwtUtil.EXPIRE_TIME_MONTH / 1000);
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        obj.put("token", token);
        obj.put("merchant", merchant);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 校验token的有效性
     *
     * @param token
     */
    public CarMerchant checkUserTokenIsEffect(String token) throws AuthenticationException {
        if (token == null){
            throw new AuthenticationException("token为空!");
        }
        // 解密获得username，用于和数据库进行对比
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            throw new AuthenticationException("token非法无效!");
        }
        // 查询用户信息
        CarMerchant carMerchant = carMerchantService.getUserByName(username);
        if (carMerchant == null) {
            throw new AuthenticationException("商户不存在!");
        }

        // 校验token是否超时失效 & 或者账号密码是否错误
        if (!jwtTokenRefresh(token, username, carMerchant.getLoginPwd())) {
            throw new AuthenticationException("Token失效，请重新登录!");
        }
        return carMerchant;
    }


    public boolean jwtTokenRefresh(String token, String userName, String passWord) {
        String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_MERCHANT_TOKEN + token));
        if (oConvertUtils.isNotEmpty(cacheToken)) {
            // 校验token有效性
            if (!JwtUtil.verify(token, userName, passWord)) {
                String newAuthorization = JwtUtil.sign(userName,CommonConstant.CLIENT_PC_B,passWord);
                redisUtil.set(CommonConstant.PREFIX_MERCHANT_TOKEN + token, newAuthorization);
                // 设置超时时间
                redisUtil.expire(CommonConstant.PREFIX_MERCHANT_TOKEN + token, JwtUtil.EXPIRE_TIME_MONTH / 1000);
            } else {
                redisUtil.set(CommonConstant.PREFIX_MERCHANT_TOKEN + token, cacheToken);
                // 设置超时时间
                redisUtil.expire(CommonConstant.PREFIX_MERCHANT_TOKEN + token, JwtUtil.EXPIRE_TIME_MONTH / 1000);
            }
            return true;
        }
        return false;
    }
}
